/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
#ifndef __HPM6450_USBD_H__
#define __HPM6450_USBD_H__

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus*/
#include "common/hpm_common.h"
#include "common/hpm_errno.h"
#include "core/include/hpm6e00_regs_usb.h"
#include <driver/usb/hpm6e00_usb.h>
#include <stdint.h>
#include <stdio.h>

/* \brief USB 设备控制器队列头数量*/
#define USB_DEVICE_QH_NUM                   16
/* \brief USB 设备控制器传输描述符数量*/
#define USB_DEVICE_TD_NUM                   64

#define USB_USBMODE_CTRL_MODE_DEVICE       (2 << USB_USBMODE_CM_POS)

#define USB_EP_SETUP_STATUS_EP0            (1 << USB_ENDPTSETUPSTAT_POS)

#define USBD_DTD_TOTAL_BYTES(tkn)        (((tkn) & USBD_DTD_TOTAL_BYTES_MASK) >> USBD_DTD_TOTAL_BYTES_POS)

/* \brief 端点状态*/
#define USBD_EP_ST_ENABLE                   0x00   /* 使能*/
#define USBD_EP_ST_DISABLE                  0x01   /* 禁能*/
#define USBD_EP_ST_RESET                    0x02   /* 复位*/

/* \brief 端口速度定义*/
#define USBD_PORTSC1_PSPD_FULL             (0x00U << USB_PORTSC1_PSPD_POS)
#define USBD_PORTSC1_PSPD_LOW              (0x01U << USB_PORTSC1_PSPD_POS)
#define USBD_PORTSC1_PSPD_HIGH             (0x02U << USB_PORTSC1_PSPD_POS)
#define USBD_PORTSC1_PSPD_UNDEF            (0x03U << USB_PORTSC1_PSPD_POS)

#define USBD_DQH_MULT_POS                  (30U)
#define USBD_DQH_MULT_MASK                 (0x3U << USBD_DQH_MULT_POS)
#define USBD_DQH_ZLT_POS                   (29U)
#define USBD_DQH_ZLT_MASK                  (0x1U << USBD_DQH_ZLT_POS)
#define USBD_DQH_MAX_PKT_POS               (16U)
#define USBD_DQH_MAX_PKT_MASK              (0x7FFU << USBD_DQH_MAX_PKT_POS)
#define USBD_DQH_ISO_POS                   (15U)
#define USBD_DQH_ISO_MASK                  (0x1U << USBD_DQH_ISO_POS)
#define USBD_DQH_STA_ACTIVE_POS            (7U)
#define USBD_DQH_STA_ACTIVE_MASK           (0x1U << USBD_DQH_STA_ACTIVE_POS)
#define USBD_DQH_STA_HALT_POS              (6U)
#define USBD_DQH_STA_HALT_MASK             (0x1U << USBD_DQH_STA_HALT_POS)

#define USBD_DTD_TOTAL_BYTES_POS           (16U)
#define USBD_DTD_TOTAL_BYTES_MASK          (0x7FFFU << USBD_DTD_TOTAL_BYTES_POS)
#define USBD_DTD_IOC_POS                   (15U)
#define USBD_DTD_IOC_MASK                  (0x1U << USBD_DTD_IOC_POS)
#define USBD_DTD_STA_ACTIVE_POS            (7U)
#define USBD_DTD_STA_ACTIVE_MASK           (0x1U << USBD_DTD_STA_ACTIVE_POS)
#define USBD_DTD_STA_HALTED_POS            (6U)
#define USBD_DTD_STA_HALTED_MASK           (0x1U << USBD_DTD_STA_HALTED_POS)
#define USBD_DTD_STA_DATA_BUFF_ERR_POS     (5U)
#define USBD_DTD_STA_DATA_BUFF_ERR_MASK    (0x1U << USBD_DTD_STA_DATA_BUFF_ERR_POS)
#define USBD_DTD_STA_TRANSACTION_ERR_POS   (3U)
#define USBD_DTD_STA_TRANSACTION_ERR_MASK  (0x1U << USBD_DTD_STA_TRANSACTION_ERR_POS)

#define USBD_DTD_ADDR_POS                  (0x5U)
#define USBD_DTD_ADDR_MASK                 (0x7FFFFFFU << USBD_DTD_ADDR_POS)

#define USB_ITC_IMMEDIATE                   0x00
#define USB_ITC_1_MICRO_FRAME              (1 << 1)
#define USB_ITC_2_MICRO_FRAME              (1 << 2)
#define USB_ITC_4_MICRO_FRAME              (1 << 3)
#define USB_ITC_8_MICRO_FRAME              (1 << 4)
#define USB_ITC_16_MICRO_FRAME             (1 << 5)
#define USB_ITC_32_MICRO_FRAME             (1 << 6)
#define USB_ITC_64_MICRO_FRAME             (1 << 7)

/* \brief 中断回调函数*/
typedef void (*p_fn_trans_done)(void *p_arg, int status, uint32_t len);

/* \brief USB 设备端点队列头结构体 */
struct usb_device_qh {
    uint32_t              info1;
    uint32_t              curr_dtd;
    uint32_t              next_dtd;
    uint32_t              info2;
    uint32_t              buff0;
    uint32_t              buff1;
    uint32_t              buff2;
    uint32_t              buff3;
    uint32_t              buff4;
    uint32_t              reserved1;
    uint8_t               setup_buf[8];
    uint32_t              reserved2[2];
    uint32_t              is_init;
    struct usb_device_td *p_td_list;
    /* 必须 64 字节对齐 */
};

/* \brief USB 设备传输描述符结构体*/
struct usb_device_td {
    uint32_t              next;
    uint32_t              token;
    uint32_t              buf[5];
    uint32_t              len;
    uint32_t              reserved[2];
    uint32_t              is_used;
    void                 *p_buf;
    void                 *p_arg;
    p_fn_trans_done       p_fn_done;
    struct usb_device_td *p_td_priv;
    struct usb_device_td *p_td_next;
};

/**
 * \brief USB 设备控制器初始化
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 *
 * \retval 成功返回 0
 */
int usb_device_init(hpm_usb_reg_t *p_usb_reg);
/**
 * \brief USB 设备控制器反初始化
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 *
 * \retval 成功返回 0
 */
int usb_device_deinit(hpm_usb_reg_t *p_usb_reg);
/**
 * \brief USB 设备控制器启动
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 *
 * \retval 成功返回 0
 */
int usb_device_start(hpm_usb_reg_t *p_usb_reg);
/**
 * \brief USB 设备控制器停止函数
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 *
 * \retval 成功返回 0
 */
int usb_device_stop(hpm_usb_reg_t *p_usb_reg);
/**
 * \brief USB 设备控制器设置地址
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] addr      要设置的地址
 *
 * \retval 成功返回 0
 */
int usb_device_addr_set(hpm_usb_reg_t *p_usb_reg, uint8_t addr);
/**
 * \brief USB 设备控制器端点初始化
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   端点地址
 * \param[in] ep_type   端点类型
 *
 * \retval 成功返回 0
 */
int usb_device_ep_init(hpm_usb_reg_t *p_usb_reg,
                       uint8_t        ep_addr,
                       uint8_t        ep_type);
/**
 * \brief USB 设备控制器端点使能
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   端点地址
 *
 * \retval 成功返回 0
 */
int usb_device_ep_enable(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr);
/**
 * \brief USB 设备控制器端点禁能
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   端点地址
 *
 * \retval 成功返回 0
 */
int usb_device_ep_disable(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr);
/**
 * \brief USB 设备控制器端点停止设置
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   端点地址
 * \param[in] is_set    是否停止
 *
 * \retval 成功返回 0
 */
int usb_device_ep_halt_set(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr, bool_t is_set);
/**
 * \brief USB 设备控制器端点 FIFO 冲刷
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   要冲刷的端点地址
 *
 * \retval 成功返回 0
 */
int usb_device_ep_fifo_flush(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr);
/**
 * \brief 队列头初始化
 */
int usb_device_qh_init(uint8_t  ep_addr,
                       uint8_t  ep_type,
                       uint16_t mpk,
                       bool_t   zlt,
                       uint8_t  mult);
/**
 * \brief 队列头获取
 *
 * \param[in] ep_addr   端点地址
 *
 * \retval 成功返回 USB 设备控制器队列头
 */
struct usb_device_qh *usb_device_qh_get(uint8_t ep_addr);
/**
 * \brief USB 设备控制器传输描述符链表制作
 *
 * \param[in] mpk       最大包大小
 * \param[in] p_buf     缓存
 * \param[in] len       缓存大小
 * \param[in] p_fn_done 传输完成回调函数
 * \param[in] p_arg     传输完成回调函数参数
 *
 * \retval 成功返回 传输描述符链表
 */
struct usb_device_td *usb_device_td_list_make(uint16_t         mpk,
                                              uint8_t         *p_buf,
                                              uint32_t         len,
                                              p_fn_trans_done  p_fn_done,
                                              void            *p_arg);
/**
 * \brief USB 设备控制器传输描述符插入
 *
 * \param[in] p_usb_reg 相关 USB 寄存器
 * \param[in] ep_addr   端点地址
 * \param[in] p_td      传输描述符链表
 *
 * \retval 成功返回 0
 */
int usb_device_ep_td_insert(hpm_usb_reg_t        *p_usb_reg,
                            uint8_t               ep_addr,
                            struct usb_device_td *p_td);
/**
 * \brief USB 设备控制器传输描述符移除
 *
 * \param[in] p_usb_reg 相关 USB 寄存器
 * \param[in] ep_addr   端点地址
 * \param[in] p_buf     传输描述符相关的缓存地址
 *
 * \retval 成功返回 0
 */
int usb_device_td_list_remove(hpm_usb_reg_t *p_usb_reg,
                              uint8_t        ep_addr,
                              uint8_t       *p_buf);
/**
 * \brief 端点传输描述符扫描函数
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   要扫描的端点地址
 *
 * \retval 成功返回 0
 */
int usb_device_ep_td_scan(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr);

#ifdef __cplusplus
}
#endif  /* __cplusplus  */
#endif

